
#include <stdio.h>
#include <iostream>
#include <vector>
#include <math.h>

#include <vlCore/Matrix4.hpp>

using namespace std;

#define _HOMOGRAPHY_TREE

//________________________BEGIN HOMOGRAPHY_HPP file__________________

struct _func_de_R_dans_R4
{
    virtual vl::fmat4 operator() (float) = 0;
    virtual vl::fmat4 prime (float) = 0;
};


struct Homography
{
    
    Homography () 
    {
        _homographies.push_back (getIdentity ());
    }
    
    Homography (_func_de_R_dans_R4 const* func)
    {
        _homographies.push_back (func);
    }
    
    Homography (Homography const& other)
    {   
//        (*this).setToIdentity();
        _homographies = other._homographies;
    }
    
    Homography (Homography const& left, Homography const& right)
    {
        _homographies = left._homographies;
        for (unsigned int i = 0; i < right._homographies.size (); i++)
            _homographies.push_back (right._homographies[i]);
    }
    
    
    Homography& operator= (_func_de_R_dans_R4 const* func)
    {
        _homographies.clear ();
        _homographies.push_back (func);
        return (*this);
        
    }
    
    Homography& operator= (Homography const& other)
    {

        (*this).setToIdentity ();
        (*this)*=other;
    }
     
    

    Homography& operator*= (Homography const& other)
    {
        for (unsigned int i = 0; i < other._homographies.size (); i++)
        {
            
        }
        return (*this);
    }
    

    
    virtual ~Homography();
    
    Homography& setToIdentity ()
    {
        _homographies.clear ();
        _homographies.push_back (getIdentity ());
    }
    
   
  
    
    virtual vl::fmat4 operator() (float *v)
    {
    }
    
    virtual vl::fmat4 operator() (int d, float *v)
    {
    }

    int size () const
    {
    }
    
//    /* creators */
    static _func_de_R_dans_R4* getIdentity ();
    static _func_de_R_dans_R4* getScaling_xy ();
    static _func_de_R_dans_R4* getTranslation_x ();
    static _func_de_R_dans_R4* getTranslation_y ();
    static _func_de_R_dans_R4* getRotatation_z ();
//    

    std::vector <_func_de_R_dans_R4 const*> _homographies;

};

struct Identity : public _func_de_R_dans_R4
{
    vl::fmat4 operator () (float v)
    {
        return vl::fmat4::getIdentity ();
    }
    
    vl::fmat4 prime (float v)
    {
        return vl::fmat4::getNull ();
    }
};

struct Scaling_xy : public _func_de_R_dans_R4
{

    vl::fmat4 operator () (float v)
    {
        return vl::fmat4::getScaling (v, v, 1);
    }
    
    vl::fmat4 prime (float)
    {
        vl::fmat4 out = vl::fmat4::getNull ();
        out.e (0, 0) = 1;
        out.e (1, 1) = 1;
        return out;
    }
};

struct Translation_x : public _func_de_R_dans_R4
{
    vl::fmat4 operator () (float v)
    {
        return vl::fmat4::getTranslation (v, 0, 0);
    }

    vl::fmat4 prime (float)
    {
        vl::fmat4 out = vl::fmat4::getNull ();
        out.e (0, 3) = 1;
        return out;
    }
    
};

struct Translation_y : public _func_de_R_dans_R4
{
    vl::fmat4 operator () (float v)
    {
        return vl::fmat4::getTranslation (0, v, 0);
    }

     vl::fmat4 prime (float)
    {
        vl::fmat4 out = vl::fmat4::getNull ();
        out.e (1, 3) = 1;
        return out;
    }
    
};

struct Rotation_z : public _func_de_R_dans_R4
{
    vl::fmat4 operator () (float v)
    {
        
        return vl::fmat4::getRotation (v * vl::fRAD_TO_DEG, 0, 0, 1);
    }

    vl::fmat4 prime (float v)
    {
        vl::fmat4 out = vl::fmat4::getRotation ((v + M_PI * 0.5) * vl::fRAD_TO_DEG , 0, 0, 1);
        out.e (2, 2) = 0;
        return out;
    }
};

/* implements singleton pattern*/
_func_de_R_dans_R4* Homography::getScaling_xy ()
{
    Scaling_xy* out = new Scaling_xy;
    return out;
}

_func_de_R_dans_R4* Homography::getTranslation_x ()
{
    Translation_x* out = new Translation_x;
    return out;
}

_func_de_R_dans_R4* Homography::getTranslation_y ()
{
    Translation_y* out = new Translation_y;
    return out;
}

_func_de_R_dans_R4* Homography::getRotatation_z ()
{
    Rotation_z* out = new Rotation_z;
    return out;
}

//________________________END HOMOGRAPHY_HPP file__________________

std::ostream& operator<< (std::ostream& output, vl::fmat4 const& m)
{
    output << m.e (0, 0) << " " << m.e (0, 1) << " " << m.e (0, 2) << " " << m.e (0, 3) << endl;
    output << m.e (1, 0) << " " << m.e (1, 1) << " " << m.e (1, 2) << " " << m.e (1, 3) << endl;
    output << m.e (2, 0) << " " << m.e (2, 1) << " " << m.e (2, 2) << " " << m.e (2, 3) << endl;
    output << m.e (3, 0) << " " << m.e (3, 1) << " " << m.e (3, 2) << " " << m.e (3, 3) << endl;
    return output;
}

using namespace vl;


struct A
{
    virtual void operator() () = 0;

};

struct B: public A
{
    virtual void operator() ()
    {
        cout << "B" << endl;
    }
};

struct C: public A
{
    virtual void operator() ()
    {
        cout << "C" << endl;
    }
};



int main (int argc, char *argv[])
{
 
    A* b = new B;
    A* c = new C;
    
    A* a;
//    a = b;
    
    delete b;
    (*b) ();
    (*a)();
    a = c;
    (*a)();
    exit (0);
    
  
    
#ifdef _HOMOGRAPHY_TREE
    cout << "ca marche " << endl;
#endif

    

    Homography ps_xy = Homography::getScaling_xy ();
    Homography pt_x = Homography::getTranslation_x ();
    Homography pt_y = Homography::getTranslation_y ();
    Homography pr_z = Homography::getRotatation_z ();

//    Homography h = Homography::getScaling_xy ();
    float s[] = {2};
    float d[] = {1};

    cout << "scaling xy" << endl;
    cout << (ps_xy) (s) << endl;
    cout << (ps_xy) (1, s) << endl;
    cout << "t x" << endl
            << (pt_x) (s) << endl
            << (pt_x) (1, s) << endl;
    cout << "t y" << endl
            << (pt_y) (s) << endl
            << (pt_y) (1, s) << endl;
    
     float r [] = {M_PI};
    cout << "r z : " << r [0] << endl
            << (pr_z) (r) << endl
            << (pr_z) (1, r) << endl;
    r [0] = 0;
    cout << "r z : " << r [0] << endl
            << (pr_z) (r) << endl
            << (pr_z) (1, r) << endl;
    r [0] = M_PI * 0.5;
    cout << "r z : " << r [0] << endl
            << (pr_z) (r ) << endl
            << (pr_z) (1, r) << endl;
    r [0] = - M_PI * 0.5;
    cout << "r z : " << r [0] << endl
            << (pr_z) (r) << endl
            << (pr_z) (1, r ) << endl;

            
//    cout << out (s) << endl;
//    cout << out (1, s) << endl;
//    cout << fmat4::getTranslation (1, 2, 3) << endl;
}